package com.learn._05spirngaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/*
 * Aspect注解
 *  1.标识当前类为切面类，为目标方法植入额外扩展功能的类;
 *
 * Order注解
 *  多个切面类时，指定切面类的执行顺序，值越小，越先执行;
 * */

@Order(10)
@Aspect
@Component
public class LogAspect {

    /*
     * 自定义切入点表达式的方法，指定那些目标方法需要被增强;
     * */
    @Pointcut("execution(public int com.learn._05spirngaop.aop.CalculatorImpl.*(..))")
    public void doTime() {
    }/*这是切面点表达式*/


    /*
     * Before注解：前置通知，在目标方法执行之前执行;
     * JoinPoint连接点对象对象
     * */
    /*@Before("doTime()")
    public void before(JoinPoint joinPoint) {
        //获取目标的名称和参数
        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());

        System.out.println("[前置通知]:" + name + "方法开始，参数为:" + args);
    }

    *//*
     * After注解：后置通知,在目标方法结束后执行【正常结束|异常结束】;
     * *//*
    @After("doTime()")
    public void after(JoinPoint joinPoint) {
        //获取目标的名称和参数
        String name = joinPoint.getSignature().getName();
        //后置通知没有权限获取到方法的返回值
        System.out.println("[后置通知]:" + name + "方法结束");
    }

    *//*
     * AfterReturning注解:返回通知
     * 1.目标方法正常结束后执行；
     * 2.有权限获取到目标方法的返回值；
     * *//*
    @AfterReturning(value = "doTime()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        String name = joinPoint.getSignature().getName();
        System.out.println("[返回通知]:" + name + "方法正常结束，返回值为:" + result);

    }

    *//*
     * AfterThrowing注解：异常通知
     * 1.目标方法抛出异常时执行;
     * 2.有权限获取异常信息;
     * *//*
    @AfterThrowing(value = "doTime()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("[异常通知]:方法抛出异常，信息为:" + ex.getMessage());
    }*/

    /*
     * Around注解：环绕通知
     * 1.等价于 前置通知+返回通知+异常通知+后置通知;
     * 2.通常包裹在 try...catch...finally....语句中;
     * */
    @Around("doTime()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;
        try {
            System.out.println("[环绕通知-前置]");//1
            result = joinPoint.proceed();///////////////执行目标方法，获取返回值
            System.out.println("[环绕通知-返回]");//2
        } catch (Throwable e) {
            System.out.println("[环绕通知-异常]");//3
            throw new RuntimeException(e);
        }finally {
            System.out.println("[环绕通知-后置]");//4
        }//内容非常好，仔细看看

        return result;
    }
}
